class Snake {

  private element: HTMLElement

  /**
   * 蛇头
   */
  private head: HTMLElement

  /**
   * 蛇身(包括蛇头)
   */
  private bodies: HTMLCollectionOf<HTMLElement>


  constructor() {
    this.element = document.getElementById("snake")!
    this.head =  this.element.querySelector("div") as HTMLElement
    this.bodies = this.element.getElementsByTagName('div')
  }

  /**
   * 获取蛇头的X轴坐标
   */
  get X() {
    return this.head.offsetLeft
  }

  /**
   * 获取蛇头的Y轴坐标
   */
  get Y() {
    return this.head.offsetTop
  }

  get snakeBody() {
    return this.bodies
  }

  moveSnake(x: number, y: number): void {
    // 判断值是否越界 0-290
    if ((x < 0 || x > 290) || (y < 0 || y > 290)) {
      throw new Error("蛇撞墙了")
    }

    // 先移动身体
    this.movBody()
    // 再移动蛇头
    this.moveBody(this.head, x, y)
    this.checkHeadBody()
  }

  /**
   * 蛇增加一节
   */
  addBody(): void {
    // 获取最后一截身体的位置
    let x = this.bodies[this.bodies.length - 1].offsetLeft
    let y = this.bodies[this.bodies.length - 1].offsetTop
    //  增加身子
    this.element.insertAdjacentHTML("beforeend", "<div></div>")
    // 设置位置
    this.moveBody(this.bodies[this.bodies.length - 1], x, y)
  }

  /**
   * 移动身体
   */
  movBody(): void {
    // 后元素的位置等于前元素的位置
    for(let i = this.bodies.length - 1; i > 0; i--) {
      // 获取前身体的位置
      let x = this.bodies[i - 1].offsetLeft
      let y = this.bodies[i - 1].offsetTop
      this.moveBody(this.bodies[i], x, y)
    }
  }

  /**
   * 给某节身子设置位置
   * @param body 
   * @param x 
   * @param y 
   */
  private moveBody(body: HTMLElement, x: number, y: number): void {
    body.style.left = x + 'px'
    body.style.top = y + 'px'
  }

  /**
   * 检查蛇头装到身体
   */
  private checkHeadBody() {
    // 获取所有身体，是否与蛇头的坐标发生重叠
    for (let i = 1; i < this.bodies.length; i++) {
      if (this.X === this.bodies[i].offsetLeft && this.Y === this.bodies[i].offsetTop) {
        throw new Error("撞到自己了")
      }
    }
  }
}

export default Snake